//
//  HACNodesComponentKLine.m
//  HStockCharts
//
//  Created by Hotacool on 2018/9/21.
//

#import "HACNodesComponentKLine.h"
#import "HACKLineNode.h"
#import "HACTecNode.h"

#define KNode (self.nodeDic[HACNodesComponentMainNodeKey])
#define kDefaultTecNodes @[@(HACTecTypeVolume), @(HACTecTypeMACD),]
static const CGFloat kTimeBarHeight = 16;
static const CGFloat kMarginTop = 2;
@interface HACNodesComponentKLine ()
//@property (nonatomic, assign) CGPoint latestPoint;//记录最后更新的一点

@property (nonatomic, assign) NSUInteger scaleLevel;
@property (nonatomic, assign) double pinScale;
@property (nonatomic, copy) NSArray<NSNumber*>* pinLineCountArray;
@end

@implementation HACNodesComponentKLine {
    NSInteger kLineCount;
}

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self initialNodes];
        [self updateFrame:frame];
    }
    return self;
}

- (void)initialNodes {
    self.pinLineCountArray = @[@(110), @(105), @(100), @(95), @(90), @(85), @(80), @(75), @(70), @(65), @(60), @(55), @(50), @(45), @(40), @(35), @(30), @(25)];
    self.scaleLevel = 7;
    kLineCount = [self.pinLineCountArray[self.scaleLevel] integerValue];
    self.visualCount = kLineCount;
    self.clipsToBounds = YES;
    
    HACKLineNode *kline = [[HACKLineNode alloc] initWithHostLayer:self.layer];
    kline.visualCount = kLineCount;
    kline.itemsSpace = 2;
    [self.nodeDic setObject:kline forKey:HACNodesComponentMainNodeKey];
    
    self.tecNodeTypes = kDefaultTecNodes;
}

- (void)setData:(HACChartData *)data {
    [super setData:data];
    [self updateFrame:self.frame];
    
    [self showLatestPointTecInfo];
}

- (void)refreshUI {
    [super refreshUI];
    [self showLatestPointTecInfo];
}

- (void)refreshUIWithData:(HACChartData *)data {
    CGPoint offset = self.contentScroll.contentOffset;
    CGFloat currentMaxContentWidth = self.contentScroll.contentSize.width;
    self.data = data;
    CGFloat __block maxWidth = self.frame.size.width;
    [self.nodeDic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, HACChartNode* _Nonnull node, BOOL * _Nonnull stop) {
        if (node.maxContentWidth > maxWidth) {
            maxWidth = node.maxContentWidth;
        }
    }];
    CGFloat minus = maxWidth - currentMaxContentWidth;
    if (minus >= 0) {
        self.contentScroll.contentSize = CGSizeMake(maxWidth, self.frame.size.height);
        if (ABS(offset.x -(currentMaxContentWidth - self.frame.size.width)) < 1) {
            self.contentScroll.contentOffset = CGPointMake(maxWidth-self.frame.size.width, 0);
        } else {
            self.contentScroll.contentOffset = offset;
        }
    }
}

- (void)endRefreshWithData:(HACChartData *)data {
    CGPoint offset = self.contentScroll.contentOffset;
    [super endRefreshWithData:data];
    //update contentsize&contentoffset
    CGFloat currentMaxContentWidth = self.contentScroll.contentSize.width;
    CGFloat __block maxWidth = self.frame.size.width;
    [self.nodeDic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, HACChartNode* _Nonnull node, BOOL * _Nonnull stop) {
        if (node.maxContentWidth > maxWidth) {
            maxWidth = node.maxContentWidth;
        }
    }];
    CGFloat minus = maxWidth - currentMaxContentWidth;
    if (minus > 0) {
        self.contentScroll.contentSize = CGSizeMake(maxWidth, self.frame.size.height);
        self.contentScroll.contentOffset = CGPointMake(minus+offset.x, 0);
    }
}

- (void)setFrame:(CGRect)frame {
    [super setFrame:frame];
    [self updateFrame:frame];
}

- (void)updateFrame:(CGRect)frame {
    self.marketTimeBar.frame = CGRectMake(0, frame.size.height - kTimeBarHeight, frame.size.width, kTimeBarHeight);
    //重置frame、relativeFrame、pointrect
    frame = CGRectMake(0, kMarginTop, frame.size.width, frame.size.height - kTimeBarHeight - kMarginTop);
    CGFloat mainNodeRate = 0.6;
    if (self.tecNodeTypes.count == 2) {
        mainNodeRate = 0.5;
    } else if (self.tecNodeTypes.count == 3) {
        mainNodeRate = 0.4;
    }
    HACChartNode *node = KNode;
    node.relativeFrame = CGRectMake(0, 0, frame.size.width, frame.size.height*mainNodeRate);
    [node setNeedsDisplay];
    if (self.tecNodeTypes.count > 0) {
        CGFloat tecbarHeight = self.tecBars.firstObject.frame.size.height;
        CGFloat tecNodeHeight = (frame.size.height - KNode.relativeFrame.size.height - self.tecNodeTypes.count * tecbarHeight)/self.tecNodeTypes.count;
        for (int i = 0; i < self.tecNodeTypes.count; i++) {
            HACTecInfoBar *tecbar = self.tecBars[i];
            tecbar.frame = CGRectMake(0, CGRectGetMaxY(node.relativeFrame), self.frame.size.width, tecbarHeight);
            __block CGFloat originY = CGRectGetMaxY(tecbar.frame);
            NSString *nodeKey = [NSString stringWithFormat:@"%@%d", HACNodesComponentTecNodeKey, i];
            if ((node = self.nodeDic[nodeKey])) {
                node.relativeFrame = CGRectMake(0, originY, frame.size.width, tecNodeHeight);
                [node setNeedsDisplay];
            }
        }
    }
    self.refreshIndicator.center = CGPointMake(-refreshOffsetX+12, KNode.relativeFrame.size.height/2);
    [self updateContentScrollSize];
}

- (void)setTecNodeTypes:(NSArray<NSNumber*> *)tecNodeTypes {
    [super setTecNodeTypes:tecNodeTypes];
    // update tec nodes frame, keep pointrect/overflow
    self.marketTimeBar.frame = CGRectMake(0, self.frame.size.height - kTimeBarHeight, self.frame.size.width, kTimeBarHeight);
    CGRect frame = CGRectMake(0, kMarginTop, self.frame.size.width, self.frame.size.height - kTimeBarHeight - kMarginTop);
    CGFloat mainNodeRate = 0.6;
    if (self.tecNodeTypes.count == 2) {
        mainNodeRate = 0.5;
    } else if (self.tecNodeTypes.count == 3) {
        mainNodeRate = 0.4;
    }
    HACChartNode *node = KNode;
    
    //overflow
    CGPoint offset = self.contentScroll.contentOffset;
    long ts, te;
    [self calculateStartIdx:&ts endIdx:&te byOffset:offset];
    //优化滑动视觉流畅性：取消可视区域整数格画线，从不可见区域开始绘图，绘制visualCount+1格区域
    CGFloat overflow = offset.x - ts*node.singleWidth;//头部越界区域
    
    node.relativeFrame = CGRectMake(0, 0, frame.size.width, frame.size.height*mainNodeRate);
    node.startIndex = ts;
    node.endIndex = te + 1;
    node.pointRect = CGRectMake(-overflow, node.pointRect.origin.y, (node.visualCount+1)*node.singleWidth, node.pointRect.size.height);
    [node setNeedsDisplay];
    if (self.tecNodeTypes.count > 0) {
        CGFloat tecbarHeight = self.tecBars.firstObject.frame.size.height;
        CGFloat tecNodeHeight = (frame.size.height - KNode.relativeFrame.size.height - self.tecNodeTypes.count * tecbarHeight)/self.tecNodeTypes.count;
        for (int i = 0; i < self.tecNodeTypes.count; i++) {
            HACTecInfoBar *tecbar = self.tecBars[i];
            tecbar.frame = CGRectMake(0, CGRectGetMaxY(node.relativeFrame), self.frame.size.width, tecbarHeight);
            __block CGFloat originY = CGRectGetMaxY(tecbar.frame);
            NSString *nodeKey = [NSString stringWithFormat:@"%@%d", HACNodesComponentTecNodeKey, i];
            if ((node = self.nodeDic[nodeKey])) {
                node.relativeFrame = CGRectMake(0, originY, frame.size.width, tecNodeHeight);
                node.startIndex = ts;
                node.endIndex = te + 1;
                node.pointRect = CGRectMake(-overflow, node.pointRect.origin.y, (node.visualCount+1)*node.singleWidth, node.pointRect.size.height);
                [node setNeedsDisplay];
            }
        }
    }
    [self showLatestPointTecInfo];
}

- (void)showLatestPointTecInfo {
    if (self.data && self.tecNodeTypes) {
        //默认显示最新点指标
        if (!self.isFocusing) {
            NSInteger tmp = KNode.actualCount - 1;
            [self refreshTecbarInfoAtIndex:tmp];
        }
    }
}

- (void)setUpMarketTimeBarWithTimeArray:(NSArray*)timesArray {
    [self addSubview:self.marketTimeBar];
    [self updateMarketTimeBar];
}

- (void)updateMarketTimeBar {
    HACKLineEntry *start =  (HACKLineEntry *)[KNode dataAtChartForIndex:KNode.startIndex];
    HACKLineEntry *middle =  (HACKLineEntry *)[KNode dataAtChartForIndex:(KNode.endIndex + KNode.startIndex -1)/2];
    HACKLineEntry *end =  (HACKLineEntry *)[KNode dataAtChartForIndex:KNode.endIndex-1];
    if (!start || !middle || !end) {
        return;
    }
    NSArray* timesArray = @[[NSString stringWithFormat:@"%lu", start.date]
                            ,[NSString stringWithFormat:@"%lu", middle.date]
                   ,[NSString stringWithFormat:@"%lu", end.date]];
    CGFloat width = self.marketTimeBar.frame.size.width / timesArray.count;
    for (int i = 0; i < timesArray.count; i++) {
        UILabel *label = [self.marketTimeBar viewWithTag:1000+i];
        if (!label) {
            label = [[UILabel alloc] init];
            label.tag = 1000+i;
            label.font = [UIFont systemFontOfSize:10];
            label.textColor = RGB_HEX(kAxisTextColor);
            label.textAlignment = NSTextAlignmentCenter;
            [self.marketTimeBar addSubview:label];
        }
        if (i  == 0) {
            label.textAlignment = NSTextAlignmentLeft;
        } else if (i == timesArray.count - 1) {
            label.textAlignment = NSTextAlignmentRight;
        } else {
            label.textAlignment = NSTextAlignmentCenter;
        }
        label.text = timesArray[i];
        label.frame = CGRectMake(i*width, 0, width, self.marketTimeBar.frame.size.height);
    }
}

#pragma mark - scroll
- (void)reactForTapGesture:(UITapGestureRecognizer *)gesture {
    [super reactForTapGesture:gesture];
    [self showLatestPointTecInfo];
}

- (void)reactForContentViewDidScroll:(UIScrollView *)scrollView {
    [super reactForContentViewDidScroll:scrollView];
    CGPoint offset = scrollView.contentOffset;
    long ts, te;
    [self calculateStartIdx:&ts endIdx:&te byOffset:offset];
    //优化滑动视觉流畅性：取消可视区域整数格画线，从不可见区域开始绘图，绘制visualCount+1格区域
    HACChartNode *node = KNode;
    CGFloat overflow = offset.x - ts*node.singleWidth;//头部越界区域
    [self.nodeDic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, HACChartNode* _Nonnull node, BOOL * _Nonnull stop) {
        node.startIndex = ts;
        node.endIndex = te + 1;
        node.pointRect = CGRectMake(-overflow, node.pointRect.origin.y, (node.visualCount+1)*node.singleWidth, node.pointRect.size.height);
        [node setNeedsDisplay];
    }];
    [self updateMarketTimeBar];
}

- (void)reactForLongPressGesture:(UILongPressGestureRecognizer *)gesture {
    CGPoint point = [gesture locationInView:self];
    if (gesture.state == UIGestureRecognizerStateBegan || gesture.state == UIGestureRecognizerStateChanged) {
        long tmpIndex = [KNode indexAtChartForCoordinate:point];// node内部index
        self.focusPoint = [KNode pointAtChartForIndex:tmpIndex];
        self.focusIndex = tmpIndex + KNode.startIndex;
        //update tecbars
        [self refreshTecbarInfoAtIndex:self.focusIndex];
    } else {
        self.focusIndex = -1;
        [self showLatestPointTecInfo];
    }
}
// 两种策略：1.每次change改变固定单位长度，缩放比分level 2.按照实际change scale计算长度，会有最大最小缩放比不固定的副作用
- (void)reactForPinchGesture:(UIPinchGestureRecognizer *)gesture {
    [self levelScaleActionForPinGesture:gesture];
//    [self customScaleActionForPinGesture:gesture];
}

- (void)levelScaleActionForPinGesture:(UIPinchGestureRecognizer*)gesture {
    if (gesture.state == UIGestureRecognizerStateBegan) {
        self.pinScale = 0;
        self.contentScroll.scrollEnabled = NO;
    } else if (gesture.state ==UIGestureRecognizerStateChanged) {
        NSInteger oldLevel = self.scaleLevel;
        CGFloat scaleChanged = fabs(gesture.scale - 1);
        if (fabs(scaleChanged - self.pinScale) > 0.1) {
            if (scaleChanged > self.pinScale) {
                self.pinScale += 0.1;
                if (gesture.scale > 1) {
                    if (self.scaleLevel < self.pinLineCountArray.count - 1) {
                        self.scaleLevel += 1;
                    }
                } else {
                    if (self.scaleLevel > 0) {
                        self.scaleLevel -= 1;
                    }
                }
            } else {
                self.pinScale -= 0.1;
                if (gesture.scale <= 1) {
                    if (self.scaleLevel < self.pinLineCountArray.count - 1) {
                        self.scaleLevel += 1;
                    }
                } else {
                    if (self.scaleLevel > 0) {
                        self.scaleLevel -= 1;
                    }
                }
            }
            CGFloat visualWidth = CGRectGetWidth(self.frame);
            NSInteger newVisualCount = [self.pinLineCountArray[self.scaleLevel] integerValue];
            CGFloat nsw= visualWidth / newVisualCount;
            if (oldLevel != self.scaleLevel) {
                ((HACKLineNode*)KNode).isMinScale = NO;
            } else {
                if (self.scaleLevel <= 0) {
                    ((HACKLineNode*)KNode).isMinScale = YES;
                    [KNode setNeedsDisplay];
                    nsw = 2.0;
                    newVisualCount = ceil(visualWidth / nsw);
                } else {
                    ((HACKLineNode*)KNode).isMinScale = NO;
                }
            }
            CGFloat oldWidth = KNode.singleWidth;
            NSInteger oldStartIndex = KNode.startIndex;
            if( gesture.numberOfTouches == 2 && oldWidth > 0 && KNode.singleWidth > 0) {
                CGPoint p1 = [gesture locationOfTouch:0 inView:self.contentScroll];
                CGPoint p2 = [gesture locationOfTouch:1 inView:self.contentScroll];
                CGPoint centerPoint = CGPointMake((p1.x+p2.x)/2, (p1.y+p2.y)/2);
                NSUInteger oldLeftArrCount = ABS(centerPoint.x - self.contentScroll.contentOffset.x) / oldWidth;
                NSUInteger newLeftArrCount = ABS(centerPoint.x - self.contentScroll.contentOffset.x) / KNode.singleWidth;
                NSInteger newStartIndex = oldStartIndex + oldLeftArrCount - newLeftArrCount;
                NSInteger newStart = newStartIndex>0?newStartIndex:0;
                NSInteger newEnd = newStart + newVisualCount;
                
                [self updateNodesWithStartIndex:newStart endIndex:newEnd visualCount:newVisualCount];
                [self updateContentScrollSize];
            }
        }
    } else if ((gesture.state == UIGestureRecognizerStateEnded) // 结束
               || (gesture.state == UIGestureRecognizerStateCancelled)
               || (gesture.state == UIGestureRecognizerStateFailed)) {
        self.contentScroll.scrollEnabled = YES;
        self.pinScale = 0;
    }
}

- (void)customScaleActionForPinGesture:(UIPinchGestureRecognizer*)gesture {
    static CGFloat _originSingleWidth = 0;
    if (_originSingleWidth==0) {
        _originSingleWidth = KNode.singleWidth;
    }
    CGFloat scale = gesture.scale;
    if (gesture.state == UIGestureRecognizerStateBegan) {
        self.contentScroll.scrollEnabled = NO;
    } else if (gesture.state ==UIGestureRecognizerStateChanged) {
        //在手势的changed过程中，每一个changed时候获取的scale值都是和begin时的值的比率
        if (ABS(scale - self.lastScale) >= kStockChartScaleFactor) {
            // 变化量大于生效阀值才调整
            CGFloat currentScale = self.lastEndScale * scale; // 当前次缩放与本次缩放最原始的比例
            if (currentScale >= kChartKLineMinScale && currentScale <= kChartKLineMaxScale) {
                ((HACKLineNode*)KNode).isMinScale = NO;
                // 调整singleWidth和visualCount
                CGFloat visualWidth = CGRectGetWidth(self.frame);
                CGFloat nsw= _originSingleWidth * currentScale;
                int newVisualCount = ceil(visualWidth / nsw);
                CGFloat oldWidth = KNode.singleWidth;
                NSInteger oldStartIndex = KNode.startIndex;
                
                if( gesture.numberOfTouches == 2 && oldWidth > 0 && KNode.singleWidth > 0) {
                    CGPoint p1 = [gesture locationOfTouch:0 inView:self.contentScroll];
                    CGPoint p2 = [gesture locationOfTouch:1 inView:self.contentScroll];
                    CGPoint centerPoint = CGPointMake((p1.x+p2.x)/2, (p1.y+p2.y)/2);
                    NSUInteger oldLeftArrCount = ABS(centerPoint.x - self.contentScroll.contentOffset.x) / oldWidth;
                    NSUInteger newLeftArrCount = ABS(centerPoint.x - self.contentScroll.contentOffset.x) / KNode.singleWidth;
                    NSInteger newStartIndex = oldStartIndex + oldLeftArrCount - newLeftArrCount;
                    NSInteger newStart = newStartIndex>0?newStartIndex:0;
                    NSInteger newEnd = newStart + newVisualCount;
                    
                    [self updateNodesWithStartIndex:newStart endIndex:newEnd visualCount:newVisualCount];
                    [self updateContentScrollSize];
                }
            } else if (currentScale <= kChartKLineMinScale) {
                // kline缩放到最小变成线
                ((HACKLineNode*)KNode).isMinScale = YES;
                [KNode setNeedsDisplay];
                [self.nodeDic[HACNodesComponentTecNodeKey] setNeedsDisplay];
            }
            self.lastScale = scale;
        }
    } else if ((gesture.state == UIGestureRecognizerStateEnded) // 结束
               || (gesture.state == UIGestureRecognizerStateCancelled)
               || (gesture.state == UIGestureRecognizerStateFailed))
    {
        // 当手指离开屏幕时,将lastEndScale设置会最后的scale,用于下次使用
        CGFloat currentScale = self.lastEndScale * scale; // 本次缩放与最原始的比例
        self.lastEndScale = MIN(MAX(kChartKLineMinScale, currentScale), kChartKLineMaxScale);
        self.contentScroll.scrollEnabled = YES;
    }
}

- (void)calculateStartIdx:(long*)ts endIdx:(long*)te byOffset:(CGPoint)offset {
    HACChartNode *node = KNode;
    long m = offset.x/node.singleWidth;
    *ts = m>=0?m:0;
    *te = (m+node.visualCount)<=node.actualCount?(m+node.actualCount):node.visualCount;
    if (m<=0) {
        //滑到最左边，左边已无更多历史数据，模拟scroll bounce左边显示空白
        *ts = 0;
        *te = m+node.visualCount-1;
    } else {
        if (m>node.actualCount-node.visualCount) {
            //滑到最右边，右边已无更多最新数据，模拟scroll bounce右边显示空白
            *ts = m;
            *te = node.actualCount-1;
        } else {
            *ts = m;
            *te = m+node.visualCount-1;
        }
    }
}

- (NSArray<NSString *> *)stringForFocusItem:(HACFocusComponents *)focusItem focusIndex:(NSInteger)focusIndex {
    NSArray *retArray;
    NSString *focusString, *focusExtString;
    HACKLineEntry *data = (HACKLineEntry *)[KNode dataAtChartForIndex:focusIndex];
    if (focusItem.axisType == DrawingAxisTypeX) {
        if ([self.delegate respondsToSelector:@selector(nodeComponent:focusAtIndex:yAxisString:extString:)]) {
            [self.delegate nodeComponent:self focusAtIndex:focusIndex yAxisString:&focusString extString:&focusExtString];
        } else {
            focusString = @(data.closePrice).stringValue;
            focusExtString = @"";
        }
    } else {
        if ([self.delegate respondsToSelector:@selector(nodeComponent:focusAtIndex:xAxisString:extString:)]) {
            [self.delegate nodeComponent:self focusAtIndex:focusIndex xAxisString:&focusString extString:&focusExtString];
        } else {
            focusString = @(data.date).stringValue;
            focusExtString = @"";
        }
    }
    retArray = @[focusString?:@"", focusExtString?:@""];
    return retArray;
}

#pragma mark --
// update nodes
- (void)updateNodesWithStartIndex:(NSInteger)start endIndex:(NSInteger)end visualCount:(NSInteger)v {
    [self updateFrame:self.frame];// 重置pointRect，取消overflow
    [self.nodeDic enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, HACChartNode * _Nonnull node, BOOL * _Nonnull stop) {
        node.visualCount = v;
        node.startIndex = start;
        node.endIndex = end;
        [node setNeedsDisplay];
    }];
}
@end
